package com.spring.security.core.validate.image;

import cn.hutool.core.util.ImageUtil;
import cn.hutool.core.util.RandomUtil;
import com.spring.security.core.properties.SecurityProperties;
import com.spring.security.core.validate.ValidateCodeGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author seabed_moon
 */
@Component("imageValidateCodeGenerator")
public class ImageValidateCodeGenerator implements ValidateCodeGenerator {

    @Autowired
    private SecurityProperties securityProperties;

    private final int interfereCount = 15;

    /**
     * @param servletWebRequest
     * @return
     */
    @Override
    public ImageCode generate(ServletWebRequest servletWebRequest) {
        int width = ServletRequestUtils.getIntParameter(servletWebRequest.getRequest(), "width", securityProperties.getCode().getImage().getWidth());
        int height = ServletRequestUtils.getIntParameter(servletWebRequest.getRequest(), "height", securityProperties.getCode().getImage().getHeight());
        final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        final ThreadLocalRandom random = RandomUtil.getRandom();

        final Graphics2D g = ImageUtil.createGraphics(image, new Color(249, 249, 249));

        // ~ 干扰线
        drawInterfere(g, random, width, height);

        // ~ 创建字体
        g.setFont(new Font("Courier", 0, (int) ((double) height * 0.75D)));

        final FontMetrics metrics = g.getFontMetrics();
        int minY = metrics.getAscent() - metrics.getLeading() - metrics.getDescent();

        // ~ 文字
        final int len = securityProperties.getCode().getImage().getLength();

        int charWidth = width / len;

        String code = RandomUtil.randomString(len);

        for (int i = 0; i < len; i++) {
            // ~ 产生随机的颜色值，让输出的每个字符的颜色值都将不同。
            g.setColor(ImageUtil.randomColor(random));
            g.drawString(String.valueOf(code.charAt(i)), i * charWidth, RandomUtil.randomInt(minY, height));
        }

        g.dispose();
        return new ImageCode(image, code, securityProperties.getCode().getImage().getExpireIn());
    }

    /**
     * 绘制干扰线
     *
     * @param g      {@link Graphics2D}画笔
     * @param random 随机对象
     */
    private void drawInterfere(Graphics2D g, ThreadLocalRandom random, int width, int height) {
        // ~ 干扰线
        for (int i = 0; i < interfereCount; i++) {
            int xs = random.nextInt(width);
            int ys = random.nextInt(height);
            int xe = xs + random.nextInt(width / 8);
            int ye = ys + random.nextInt(height / 8);
            g.setColor(ImageUtil.randomColor(random));
            g.drawLine(xs, ys, xe, ye);
        }
    }

    public SecurityProperties getSecurityProperties() {
        return securityProperties;
    }

    public void setSecurityProperties(SecurityProperties securityProperties) {
        this.securityProperties = securityProperties;
    }
}
